﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Data.Objects;

namespace Macds.Data
{
    /// <summary>
    /// A generic repository for working with data in the database
    /// </summary>
    /// <typeparam name="T">A POCO that represents an Entity Framework entity</typeparam>
    public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
    {
        /// <summary>
        /// The context object for the database
        /// </summary>
        private ObjectContext _context;

        /// <summary>
        /// The IObjectSet that represents the current entity.
        /// </summary>
        private IObjectSet<TEntity> _objectSet;

        /// <summary>
        /// The public context object for the database
        /// </summary>
        public ObjectContext Context
        {
            get { return _context; }
        }

        /// <summary>
        /// Initializes a new instance of the GenericRepository class
        /// </summary>
        /// <param name="context">The Entity Framework ObjectContext</param>
        public Repository(ObjectContext context)
        {
            _context = context;
            _objectSet = _context.CreateObjectSet<TEntity>();
        }

        /// <summary>
        /// See <see cref="IRepository.GetQuery"/>
        /// </summary>
        public IQueryable<TEntity> GetQuery()
        {
            return _objectSet;
        }

        /// <summary>
        /// See <see cref="IRepository.GetAll"/>
        /// </summary>
        public IEnumerable<TEntity> GetAll()
        {
            return GetQuery().AsEnumerable();
        }

        /// <summary>
        /// See <see cref="IRepository.Find(Expression<Func<TEntity, bool>>)"/>
        /// </summary>
        public IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
        {
            return _objectSet.Where<TEntity>(predicate);
        }

        /// <summary>
        /// See <see cref="IRepository.Single(Expression<Func<TEntity, bool>>)"/>
        /// </summary>
        public TEntity Single(Expression<Func<TEntity, bool>> predicate)
        {
            return _objectSet.Single<TEntity>(predicate);
        }

        /// <summary>
        /// See <see cref="IRepository.First(Expression<Func<TEntity, bool>>)"/>
        /// </summary>
        public TEntity First(Expression<Func<TEntity, bool>> predicate)
        {
            return _objectSet.First<TEntity>(predicate);
        }

        /// <summary>
        /// See <see cref="IRepository.Delete(TEntity)"/>
        /// </summary>
        public void Delete(TEntity entity)
        {
            if (entity == null)
            {
                throw new ArgumentNullException("entity");
            }

            _objectSet.DeleteObject(entity);
        }

        /// <summary>
        /// See <see cref="IRepository.Add(TEntity)"/>
        /// </summary>
        public void Add(TEntity entity)
        {
            if (entity == null)
            {
                throw new ArgumentNullException("entity");
            }

            _objectSet.AddObject(entity);
        }

        /// <summary>
        /// See <see cref="IRepository.Attach(TEntity)"/>
        /// </summary>
        public void Attach(TEntity entity)
        {
            _objectSet.Attach(entity);
        }

        /// <summary>
        /// See <see cref="IRepository.Detach(TEntity)"/>
        /// </summary>
        public void Detach(TEntity entity)
        {
            _objectSet.Detach(entity);
        }

        /// <summary>
        /// See <see cref="IRepository.SaveChanges"/>
        /// </summary>
        public void SaveChanges()
        {
            _context.SaveChanges();
        }

        /// <summary>
        /// See <see cref="IRepository.SaveChanges(SaveOptions)"/>
        /// </summary>
        public void SaveChanges(SaveOptions options)
        {
            _context.SaveChanges(options);
        }

        /// <summary>
        /// Releases all resources used by the WarrantManagement.DataExtract.Dal.ReportDataBase
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// Releases all resources used by the WarrantManagement.DataExtract.Dal.ReportDataBase
        /// </summary>
        /// <param name="disposing">A Boolean value indicating whether or not to dispose managed resources</param>
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_context != null)
                {
                    _context.Dispose();
                    _context = null;
                }
            }
        }
    }

}
